package users

import (
	"context"

	"myapp/internal/consts"
	"myapp/internal/dao"
	"myapp/internal/model"
	"myapp/internal/model/do"
	"myapp/internal/model/entity"

	"myapp/internal/service"

	"github.com/gogf/gf/v2/crypto/gaes"
	"github.com/gogf/gf/v2/encoding/gbase64"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/grand"
)

type sMember struct{}

func init() {
	service.RegisterMember(New())
}

func New() *sMember {
	return &sMember{}
}

// 注册相关
func (u *sMember) Register(ctx context.Context, in model.RegisterInput) error {
	if err := u.checkUser(ctx, in.Username); err != nil {
		return err
	}
	salt := grand.S(16)
	pwd, err := u.encrypt(in.Password, salt)
	if err != nil {
		return err
	}

	_, err = dao.Member.Ctx(ctx).Data(do.Member{
		Username:   in.Username,
		Pwd:        pwd,
		Salt:       salt,
		CreateTime: gtime.Now(),
	}).Insert()
	if err != nil {
		return err
	}
	return nil
}

// 检查用户名是否存在
func (u *sMember) checkUser(ctx context.Context, username string) error {
	count, err := dao.Member.Ctx(ctx).Where("username", username).Count()
	if err != nil {
		return err
	}
	if count > 0 {
		return gerror.New("用户已存在")
	}
	return nil
}

/**
 * aes 加解密
 */
func (u *sMember) encrypt(plainText string, lvs string) (string, error) {
	key := []byte(consts.AesKEY)

	// iv 长度必须等于blockSize，只能为16
	iv := []byte(lvs)

	// 加密
	cipherText, err := gaes.Encrypt([]byte(plainText), key, iv)
	if err != nil {
		return "", err
	}
	s := gbase64.EncodeToString(cipherText)
	return s, nil
}
func (u *sMember) decrypt(plainText string, lvs string) (string, error) {
	b, err := gbase64.DecodeString(plainText)
	if err != nil {
		return "", err
	}

	key := []byte(consts.AesKEY)

	// iv 长度必须等于blockSize，只能为16
	iv := []byte(lvs)

	// 加密
	cipherText, err := gaes.Decrypt(b, key, iv)
	if err != nil {
		return "", err
	}
	return string(cipherText), nil
}

// 登陆
func (u *sMember) Login(ctx context.Context, username, password string) (tokenString string, err error) {
	var user entity.Member
	err = dao.Member.Ctx(ctx).Where("username", username).Scan(&user)
	if err != nil {
		return "", gerror.New("用户名或密码错误")
	}

	if user.Id == 0 {
		return "", gerror.New("用户不存在")
	}

	// 将密码加密后与数据库中的密码进行比对
	pwd, err := u.decrypt(user.Pwd, user.Salt)
	if err != nil {
		return "", err

	}
	if pwd != password {
		return "", gerror.New("用户名或密码错误")
	}

	return service.JwtToken().CreateToken(ctx, user.Id, user.Username)
}

// 登陆 使用 session 登录
func (u *sMember) LoginWS(ctx context.Context, username, password string) (tokenString string, err error) {
	var user entity.Member
	err = dao.Member.Ctx(ctx).Where("username", username).Scan(&user)
	if err != nil {
		return "", gerror.New("用户名或密码错误")
	}

	if user.Id == 0 {
		return "", gerror.New("用户不存在")
	}

	// 将密码加密后与数据库中的密码进行比对
	pwd, err := u.decrypt(user.Pwd, user.Salt)
	if err != nil {
		return "", err

	}
	if pwd != password {
		return "", gerror.New("用户名或密码错误")
	}

	// 设置session值
	if err := service.Session().SetUser(ctx, &model.SessionUser{
		Id:       user.Id,
		Username: user.Username,
	}); err != nil {
		return "", err
	}
	// 自动更新上线
	service.CustomContext().SetContextUser(ctx, &model.CustomContextUser{
		Id:       user.Id,
		UserName: user.Username,
	})

	return "", nil
}

// 用户详情
func (u *sMember) Detail(ctx context.Context) (user *entity.Member, err error) {
	user = &entity.Member{}
	customContext := service.CustomContext().Get(ctx)
	err = dao.Member.Ctx(ctx).Where("id", customContext.User.Id).FieldsEx("password").Scan(&user)
	if err != nil {
		return nil, err
	}

	// 禁止暴露密码
	user.Pwd = ""
	return
}
